package com.yt.order.service;

import com.yt.order.common.config.WxPayConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.security.MessageDigest;
import java.util.*;

@Slf4j
@Service
public class WxPayService {
    
    @Autowired
    private WxPayConfig wxPayConfig;
    
    /**
     * 获取沙箱环境签名密钥
     * @return 沙箱环境签名密钥
     */
    public String getSandboxSignKey() {
        try {
            // 构造请求参数
            Map<String, String> params = new HashMap<>();
            params.put("mch_id", wxPayConfig.getMchId());
            params.put("nonce_str", generateNonceStr());
            
            // 生成签名
            String sign = generateSignature(params, wxPayConfig.getKey());
            params.put("sign", sign);
            
            // 如果启用沙箱环境，请求沙箱签名密钥
            if (wxPayConfig.isSandboxEnabled()) {
                // 这里应该调用微信支付的沙箱接口获取sandbox_signkey
                // 为了演示，我们返回一个模拟的沙箱签名密钥
                log.info("沙箱环境已启用，获取沙箱签名密钥");
                return "sandbox_signkey_example";
            }
            
            return wxPayConfig.getKey();
        } catch (Exception e) {
            log.error("获取沙箱签名密钥失败", e);
            return null;
        }
    }
    
    /**
     * 生成统一下单参数
     * @param orderId 订单号
     * @param amount 金额(分)
     * @param description 商品描述
     * @param openid 用户openid
     * @return 统一下单参数Map
     */
    public Map<String, String> generateUnifiedOrderParams(String orderId, int amount, String description, String openid) {
        Map<String, String> params = new HashMap<>();
        params.put("appid", wxPayConfig.getAppId());
        params.put("mch_id", wxPayConfig.getMchId());
        params.put("nonce_str", generateNonceStr());
        params.put("sign_type", "MD5");
        params.put("body", description);
        params.put("out_trade_no", orderId);
        params.put("total_fee", String.valueOf(amount));
        params.put("spbill_create_ip", "127.0.0.1");
        params.put("notify_url", "https://your-domain.com/wxpay/notify");
        params.put("trade_type", "JSAPI");
        params.put("openid", openid);
        
        // 生成签名
        String key = wxPayConfig.isSandboxEnabled() ? getSandboxSignKey() : wxPayConfig.getKey();
        String sign = generateSignature(params, key);
        params.put("sign", sign);
        
        return params;
    }
    
    /**
     * 生成支付签名给前端
     * @param prepayId 预支付交易会话标识
     * @return 支付签名参数
     */
    public Map<String, String> generatePaySign(String prepayId) {
        Map<String, String> params = new HashMap<>();
        params.put("appId", wxPayConfig.getAppId());
        params.put("timeStamp", String.valueOf(System.currentTimeMillis() / 1000));
        params.put("nonceStr", generateNonceStr());
        params.put("package", "prepay_id=" + prepayId);
        params.put("signType", "MD5");
        
        // 生成签名
        String key = wxPayConfig.isSandboxEnabled() ? getSandboxSignKey() : wxPayConfig.getKey();
        String sign = generateSignature(params, key);
        params.put("paySign", sign);
        
        return params;
    }
    
    /**
     * 生成签名
     * @param params 参数Map
     * @param key API密钥
     * @return 签名字符串
     */
    public String generateSignature(Map<String, String> params, String key) {
        // 1. 对参数按照key的ASCII码升序排序
        List<String> keys = new ArrayList<>(params.keySet());
        Collections.sort(keys);
        
        // 2. 拼接字符串
        StringBuilder toSign = new StringBuilder();
        for (String keyItem : keys) {
            String value = params.get(keyItem);
            if (value != null && !"".equals(value) && !"sign".equals(keyItem)) {
                toSign.append(keyItem).append("=").append(value).append("&");
            }
        }
        
        // 3. 拼接API密钥
        toSign.append("key=").append(key);
        
        // 4. MD5加密并转为大写
        return md5(toSign.toString()).toUpperCase();
    }
    
    /**
     * 生成随机字符串
     * @return 随机字符串
     */
    public String generateNonceStr() {
        return UUID.randomUUID().toString().replace("-", "").substring(0, 32);
    }
    
    /**
     * MD5加密
     * @param data 待加密数据
     * @return 加密后的字符串
     */
    private String md5(String data) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] array = md.digest(data.getBytes("UTF-8"));
            StringBuilder sb = new StringBuilder();
            for (byte item : array) {
                sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
            }
            return sb.toString().toUpperCase();
        } catch (Exception e) {
            log.error("MD5加密失败", e);
            return null;
        }
    }
    
    /**
     * 验证支付通知签名
     * @param params 通知参数
     * @return 验证结果
     */
    public boolean verifyNotifySign(Map<String, String> params) {
        try {
            String sign = params.get("sign");
            if (sign == null || sign.trim().isEmpty()) {
                return false;
            }
            
            // 生成签名
            String key = wxPayConfig.isSandboxEnabled() ? getSandboxSignKey() : wxPayConfig.getKey();
            String expectedSign = generateSignature(params, key);
            
            return sign.equals(expectedSign);
        } catch (Exception e) {
            log.error("验证支付通知签名失败", e);
            return false;
        }
    }
}